#include "common.h"

#ifndef __GXL_THREAD__
#define __GXL_THREAD__

#include "ts_dique.h"
#include "util.h"

namespace GXL_Engine
{
	class Runnable
	{
	public:
		Runnable(){}
		virtual ~Runnable(){}
		virtual VOID Run() = 0;
	};

	typedef TSDique<Runnable*> 		TaskList;

	class Thread
	{
		friend static unsigned long WINAPI thread_proc(void* param);

	public:
		Thread();
		virtual ~Thread();

		UINT32		AddTask(Runnable* pRunnable);
		UINT32		ShutDown();
		UINT32		Suspend();
		UINT32		Resume();
		VOID		Join();

	private:
		HANDLE		m_hThread;
		UINT32		m_dwThreadID;
		TaskList	m_taskQueue;
		BOOL		m_bShutDown;
	};

	template<typename T>
	class Threader
	{
		typedef std::map<UINT32, HANDLE>	ThreadMap;
		typedef	std::pair<UINT32, HANDLE>	ThreadPair;
		typedef VOID (T::*MemFun)();
		static unsigned long WINAPI thread_proc(void* param)
		{
			GXL_Engine::CallBack<T>* pCallBack = (GXL_Engine::CallBack<T>*)param;
			pCallBack->Run();
			return 0;
		}
	public:
		UINT32	StartThread(MemFun pFun, LPCSTR szThreadName)
		{
			UINT32 dwThreadID = GXL_Engine::Util::Crc32(szThreadName);
			if (m_mapThreads.find(dwThreadID) != m_mapThreads.end())
			{
				return -1;
			}

			GXL_Engine::CallBack<T>* pCallBack = new GXL_Engine::CallBack<T>((T*)this, pFun);

			HANDLE hThread = CreateThread(NULL, 0, thread_proc, pCallBack, 0, 0);
			m_mapThreads.insert(ThreadPair(dwThreadID, hThread));

			return 0;
		}
		UINT32	WaitThread(LPCSTR szThreadName = NULL)
		{
			if (P_VALID(szThreadName))
			{
				UINT32 uThreadID = Util::Crc32(szThreadName);
				ThreadMap::iterator itr = m_mapThreads.find(uThreadID);
				if (itr != m_mapThreads.end())
				{
					WaitForSingleObject(itr->second, INFINITE);
					return 0;
				}
				return -1;

			} 
			else
			{
				ThreadMap::iterator itr = m_mapThreads.begin();
				while (itr != m_mapThreads.end())
				{
					WaitForSingleObject(itr->second, INFINITE);
					++itr;
				}
				return 0;
			}			
		}
	private:
		ThreadMap		m_mapThreads;
	};


}//namespace GXL_Engine
#endif //__GXL_THREAD__